import json
import logging
import math
from datetime import date, datetime, timedelta
from decimal import Decimal
from typing import Literal

from asgiref.sync import sync_to_async
from auditlog.context import disable_auditlog, set_actor
from django.contrib.auth import authenticate, get_user
from django.contrib.auth.models import User
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.db.models import CharField, F, Q, Value
from django.db.models.functions import Concat
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils import timezone
from ninja import Form, Router, Schema
from ninja.errors import HttpError
from ninja.files import UploadedFile
from ninja.orm import create_schema

from decorators.auth_login import login_for_logs_by_mpp
from .models import Contract, ContractProduct, Product, ProductSection, StockRecord, Users

router = Router(tags=["orders"])

@router.get("/hello")
def hello(request) -> Literal["Hello world"]:  # noqa: ARG001
    return "Hello world"


class AuthSchemaOut(Schema):
    username: str
    fio_short: str
    dolzh: str
    groups: list[str]

@router.post("/login/", auth=None)
@sync_to_async
# @login_for_logs_by_mpp
def login(request, username: Form[str], password: Form[str]) -> AuthSchemaOut:
    user: User = authenticate(request, username=username, password=password)
    users_item = Users.objects.filter(user=user).first()
    return {"username": user.username, "fio_short": users_item.fio_short, "dolzh": users_item.dolzh, "groups": users_item.groupa}


class SectionAddSchema(Schema):
    section_name: str
    username: str


@router.post("/product_section_add/")
@login_for_logs_by_mpp
def product_section_add(request, section_data: SectionAddSchema):  # noqa: ARG001, ANN201
    if ProductSection.objects.filter(name=section_data.section_name).exists():
        return {"status": 201, "ok": False}
    ProductSection.objects.create(name=section_data.section_name)
    return {"status": 200, "ok": True}


class ProductAddSchema(Schema):
    section_id: int
    product_name: str
    username: str
    measure: str
    warehouse: float


@router.post("/product_add/")
@login_for_logs_by_mpp
def product_add(request, product_data: ProductAddSchema):  # noqa: ARG001, ANN201
    if Product.objects.filter(name=product_data.product_name).exists():
        return {"status": 201, "ok": False}
    section = ProductSection.objects.get(id=product_data.section_id)
    Product.objects.create(name=product_data.product_name, product_section=section, measure=product_data.measure, warehouse=product_data.warehouse)
    return {"status": 200, "ok": True}


class ProductSectionSchema(Schema):
    id: int
    name: str

@router.get("/product_sections/", response=list[ProductSectionSchema])
def  product_sections(request):  # noqa: ARG001, ANN201
    return ProductSection.objects.all()

class ProductsSchema(Schema):
    id: int
    name: str
    measure: str
    warehouse: float

@router.get("/products/", response=list[ProductsSchema])
def prod_orders(request, section_id: int):  # noqa: ANN201, ARG001
    prod_section = ProductSection.objects.get(id=section_id)
    return Product.objects.filter(product_section=prod_section)


@router.get("/get_one_product_by_id/", response=ProductsSchema)
def get_one_product_by_id(request, product_id: int):  # noqa: ANN201, ARG001
    return get_object_or_404(Product, id=product_id)


class ContractSchema(Schema):
    id: int
    organization_name: str
    contract_number: str
    start_date: date
    end_date: date
    is_active: bool


class ProductContractsSchema(Schema):
    id: int
    contract: ContractSchema
    oms_full: float
    oms_balance: float
    oms_percent: int
    ob_full: float
    ob_balance: float
    ob_percent: int
    pd_full: float
    pd_balance: float
    pd_percent: int
    product: ProductsSchema


@router.get("/product_contracts/", response=list[ProductContractsSchema])
def product_contracts(request, product_id: int):  # noqa: ANN201, ARG001
    return ContractProduct.objects.filter(product__id=product_id, contract__end_date__gt=timezone.now())


@router.get("/product_contract/", response=ProductContractsSchema)
def product_contract(request, contract_product_id: int):  # noqa: ANN201, ARG001, F811
    return ContractProduct.objects.filter(id=contract_product_id, contract__end_date__gt=timezone.now()).first()


class OrdersSchema(Schema):
    id: int
    document_date: date
    incoming_weight: Decimal
    outgoing_weight: Decimal
    incoming_document: str


class OrdersFullOutSchema(Schema):
    oms_docs: list[OrdersSchema] = None
    ob_docs: list[OrdersSchema] = None
    pd_docs: list[OrdersSchema] = None
    out_docs: list[OrdersSchema] = None


@router.get("/orders_list/", response=OrdersFullOutSchema)
def orders_list(request, contract_id):  # noqa: ANN201, ARG001
    docs =  StockRecord.objects.filter(contract_product__id=contract_id)
    oms_docs = docs.filter(stock_code="oms")
    ob_docs = docs.filter(stock_code="ob")
    pd_docs = docs.filter(stock_code="pd")
    out_docs = docs.filter(stock_code="out")
    return {"oms_docs": oms_docs, "ob_docs": ob_docs, "pd_docs": pd_docs, "out_docs": out_docs}


class StockDocumentInSchema(Schema):
    contract_product_id: int
    document_date: date
    income: Decimal
    outcome: Decimal
    fond: str
    username: str
    incoming_document: str


@router.post("/add_stock/")
@login_for_logs_by_mpp
def add_stock(request, document: StockDocumentInSchema) -> int:  # noqa: ARG001\
    print(document)
    contruct_product = ContractProduct.objects.get(id=document.contract_product_id)
    StockRecord.objects.create(contract_product=contruct_product, document_date=document.document_date, incoming_weight=document.income, outgoing_weight=document.outcome, stock_code=document.fond, incoming_document=document.incoming_document)
    return 200


class StockDocumentDeleteInSchema(Schema):
    username: str = None
    document_id: int = None


@router.delete("/delete_stock/")
@login_for_logs_by_mpp
def delete_stock(request, body: StockDocumentDeleteInSchema):  # noqa: ANN201, ARG001
    print(body)
    stock = get_object_or_404(StockRecord, id=body.document_id)
    stock.delete()
    return {"success": True}


class ContractSchema(Schema):
    id: int
    organization_name: str
    contract_number: str
    is_closed: bool
    start_date: date
    end_date: date
    is_active: bool
    # organization_name = models.TextField(max_length=500, verbose_name="Организация")
    # contract_number = models.CharField(max_length=100, verbose_name="Номер договора")
    # is_closed = models.BooleanField(default=False, verbose_name="Активен")
    # start_date = models.DateField(verbose_name="Дата начала договора")
    # end_date = models.DateField(verbose_name="Дата окончания договора")

@router.get("/get_contract/", response=list[ContractSchema])
def get_contract(request):  # noqa: ANN201, ARG001
    return Contract.objects.all()


class ContractsSelectSchema(Schema):
    id: int
    name: str
    start_date: datetime
    disabled: bool = None


@router.get("/get_contract_select/", response=list[ContractsSelectSchema])
def get_contract_select(request, product_id):  # noqa: ANN201, ARG001
    zero_dict = {"id": 0, "name": "Выберите договор", "disabled": True, "start_date": timezone.now()}
    uses = ContractProduct.objects.filter(product__id=product_id).values("contract__id")
    contract_skip = [x["contract__id"] for x in uses]
    print(contract_skip)
    contracts = list(Contract.objects.exclude(id__in=contract_skip).filter(end_date__gte=timezone.now(), is_closed=False).annotate(name=Concat(F("organization_name"), Value(" "), F("contract_number"), output_field=CharField() )).values("id",  "name",  "start_date"))
    print(contracts)
    return [zero_dict, *contracts]


class ContractAddSchema(Schema):
    organization_name: str
    contract_number: str
    date_start: date
    date_end: date
    username: str


@router.post("/contract_add/")
def contract_add(request, contract_data: ContractAddSchema) -> int:  # noqa: ARG001
    Contract.objects.create(organization_name=contract_data.organization_name, contract_number=contract_data.contract_number, start_date=contract_data.date_start, end_date=contract_data.date_end)
    return 200


class ContractProductSchemaIn(Schema):
    oms_full: Decimal
    oms_balance: Decimal
    ob_full: Decimal
    ob_balance: Decimal
    pd_full: Decimal
    pd_balance: Decimal
    product_id: int
    contract_id: int
    username: str


@router.post("/contract_product_add/")
@login_for_logs_by_mpp
def contract_add(request, contract_data: ContractProductSchemaIn):  # noqa: ARG001, F811, ANN201
    contract = Contract.objects.get(id=contract_data.contract_id)
    product = Product.objects.get(id=contract_data.product_id)
    ContractProduct.objects.create(contract=contract, oms_full=contract_data.oms_full, ob_full=contract_data.ob_full, pd_full=contract_data.pd_full, oms_balance=contract_data.oms_balance, ob_balance=contract_data.ob_balance, pd_balance=contract_data.pd_balance, product=product)
    return 200


class DeleteContractSchema(Schema):
    contract_id: int
    username: str


@router.delete("/delete_contract/")
@login_for_logs_by_mpp
def delete_contract(request, body: DeleteContractSchema):  # noqa: ANN201, ARG001
    contract = get_object_or_404(Contract, id=body.contract_id)
    contract.delete()
    return {"success": True}
